import { PublishLaya2Base } from "./PublishLaya2Base";
import { IPublishVo, IProjectVo } from "../data/Config";
import { existsSync, readFileSync, writeFileSync, readdirSync } from "fs";
import { delDir, cpFile, moveFile } from "../utils/FileUtil";
let path = require("path");

export class VivoPublish extends PublishLaya2Base {
    get projDir() { return "vivogame"; }
    get libJs() { return "laya.vvmini.js"; }
    private _vivoProjPath: string;
    private _isDebug: boolean;
    init(publishVo: IPublishVo, projectInfo: IProjectVo) {
        super.init(publishVo, projectInfo);
        this._isDebug = !this._publishVo.content.chkRelease;
        this._vivoProjPath = this.mProjPath;
        this.mProjPath = path.join(this.mOutPath, this.projDir, "src");
    }


    async createProject() {
        let toPath = this._vivoProjPath
        // npm view @vivo-minigame/cli version
        // npm install -g @vivo-minigame/cli
        let remoteVersion, localVersion;
        let isGetRemote, isGetLocal;
        let isUpdateGlobalQGame = true;
        remoteVersion = await this.exec("npm view  @vivo-minigame/cli version");
        if (remoteVersion) {
            isGetRemote = true;
        }
        localVersion = await this.exec("mg -v");
        if (localVersion) {
            isGetLocal = true;
        }

        if (isGetLocal && isGetRemote) {
            isUpdateGlobalQGame = remoteVersion != localVersion;
            console.log(`remoteVersion: ${remoteVersion}, localVersion: ${localVersion}`);
        } else {
            console.log("Failed to get the local or remote version number");
        }

        if (isUpdateGlobalQGame) {
            this.log("全局安装@vivo-minigame/cli");
            await this.exec("npm i @vivo-minigame/cli -g");
        }

        let isProjExist = existsSync(toPath + "/node_modules") && existsSync(toPath + "/sign");
        if (isProjExist) {
            // 检测是否需要升级
            let packageCon = readFileSync(`${toPath}/package.json`, "utf8");
            let minigamePath = path.join(toPath, "minigame.config.js");
            if (packageCon.includes("@vivo-minigame/cli-service") && existsSync(minigamePath)) {
                //不需要创建项目
                await this.doPack();
                return;
            }
        }
        if (existsSync(toPath)) {
            delDir(toPath);
        }
        this.log("开始创建vivo快游戏项目");
        await this.exec(`mg init ${this.projDir}`, { cwd: this.mOutPath });
        await this.doPack();
    }

    async doPack() {
        await this.copyDir(this.mTempProjPath, this.mProjPath);
        await this.buildProject();
        await this._copyIcon();
        await this._copySign();
        this._createMainFast();
        await this._copyEngine();
        await this._buildRpk();
        this.packOver();
    }

    private async _copyIcon() {
        if (this._publishVo.content && this._publishVo.content.icon) {
            cpFile(this._publishVo.content.icon, path.join(this.mProjPath, "image\/logo.png"));
        }
        this.log("复制icon");
    }

    private async _copySign() {
        this.log("复制签名");
        if (!this._isDebug) {
            if (this._publishVo.content && this._publishVo.content.cert) {
                await this.copyDir(this._publishVo.content.cert, path.join(this._vivoProjPath, "sign\/release"));
            } else {
                this.log("正式版秘钥不能为空");
            }
        }
    }

    private _createMainFast() {
        // 修改manifest.json文件
        let manifestPath = path.join(this.mProjPath, "manifest.json");
        if (!existsSync(manifestPath)) {
            return;
        }
        let manifestContent = readFileSync(manifestPath, "utf8");
        let manifestJson = JSON.parse(manifestContent);
        manifestJson.package = this._publishVo.content.appId;
        manifestJson.name = this._publishVo.content.name || this.mProjectInfo.name;
        // manifestJson.orientation = config.vivoInfo.orientation;
        manifestJson.config.logLevel = this._isDebug ? "debug" : "off";
        // manifestJson.deviceOrientation = config.vivoInfo.orientation;
        manifestJson.versionName = this._version;
        manifestJson.versionCode = this._publishVo.content.versionCode;
        manifestJson.minPlatformVersion = this._publishVo.content.minSdkVersion || "1057";
        // manifestJson.icon = `/${path.basename(config.vivoInfo.icon)}`;
        delete manifestJson.subpackages;
        // 增加thirdEngine字段
        let EngineVersion = this.getEngineVersion();
        if (EngineVersion) {
            manifestJson.thirdEngine = {
                "laya": EngineVersion
            };
        }
        writeFileSync(manifestPath, JSON.stringify(manifestJson, null, 4), "utf8");
        // 修改game.js文件
        let content = `require("./qgame-adapter.js");\nif(!window.navigator)\n\twindow.navigator = {};
        \nwindow.navigator.userAgent = 'Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/603.1.30 (KHTML, like Gecko) Mobile/14E8301 VVGame NetType/WIFI Language/zh_CN';
require("./libs/${this.libJs}");\nwindow.config=require("./config.js");\nrequire("./index.js");`;
        let gameJsPath = path.join(this.mProjPath, "game.js");
        writeFileSync(gameJsPath, content, "utf8");

        // vivo项目，修改index.js
        let filePath = path.join(this.mProjPath, "index.js");
        if (!existsSync(filePath)) {
            return;
        }
        let fileContent = readFileSync(filePath, "utf8");
        fileContent = fileContent.replace(/loadLib(\(['"])/gm, "require$1./");
        writeFileSync(filePath, fileContent, "utf8");
    }

    private async _copyEngine() {
        // 将js/bundle.js | libs/*.* qgame-adapter.js 全放到engine文件夹中
        let indexJsStr = "index.js";
        let bundleJsStr = "js/bundle.js";
        let physicsLibsPathList = [];

        // 修改index.js，去掉物理库前面的libs
        let filePath = path.join(this.mProjPath, indexJsStr);
        let fileContent = readFileSync(filePath, "utf8");
        let physicsNameList = [];

        if (fileContent.includes(bundleJsStr)) {
            let adapterJsPath = path.join(this.mProjPath, bundleJsStr);
            physicsNameList.push(bundleJsStr);
            physicsLibsPathList.push(adapterJsPath);
        }
        let libsList = readdirSync(path.join(this.mProjPath, "libs"));
        let libsFileName, libsFilePath;
        for (let i = 0, len = libsList.length; i < len; i++) {
            libsFileName = libsList[i];
            libsFilePath = path.join(this.mProjPath, "libs", libsFileName);
            physicsNameList.push(`libs/${libsFileName}`);
            physicsLibsPathList.push(libsFilePath);
        }
        if (physicsLibsPathList.length > 0) {
            let adapterJsPath = path.join(this.mProjPath, "qgame-adapter.js");
            physicsNameList.push("qgame-adapter.js");
            physicsLibsPathList.push(adapterJsPath);
        }

        this.configVivoConfigFile(physicsNameList);
        for (let i = 0; i < physicsLibsPathList.length; i++) {
            moveFile(physicsLibsPathList[i], path.join(this._vivoProjPath, "engine", physicsNameList[i]))
        }
    }

    private async _buildRpk() {
        if (this._isDebug) {
            await this.exec("npm run build", { cwd: this._vivoProjPath });
        } else {
            await this.exec("npm run release", { cwd: this._vivoProjPath });
        }
    }

    showPreView() {
        let reg = new RegExp(/((?:http:\/\/)(?:.[\w]+)+)/g);
        let cp = this.spawn("npm.cmd", ["run", "server"], { cwd: this._vivoProjPath }, (log: string) => {
            let result = reg.exec(log);
            if (result) {
                this.update({
                    url: result, pid: cp.pid, onClose: () => {
                        this.exec("taskkill /pid " + cp.pid + " /f /t");
                    }
                });
            }
        });
    }

    getEngineVersion() {
        let workSpaceDir = this._publishVo.fromPath;
        let coreLibPath = path.join(workSpaceDir, "libs", "laya.core.js");
        let isHasCoreLib = existsSync(coreLibPath);
        let EngineVersion;
        if (isHasCoreLib) {
            let con = readFileSync(coreLibPath, "utf8");
            let matchList = con.match(/Laya\.version\s*=\s*['"]([0-9\.]+(beta)?.*)['"]/);
            if (!Array.isArray(matchList)) {
                return null;
            }
            EngineVersion = matchList[1];
        }
        return EngineVersion;
    }

    configVivoConfigFile(engineFileList) {
        let vvConfigPath = path.join(this._vivoProjPath, "minigame.config.js");
        let content = readFileSync(vvConfigPath, "utf8");
        let externalsStr = 'const externals = [\n';
        let libName;
        for (let i = 0, len = engineFileList.length; i < len; i++) {
            libName = engineFileList[i];
            if (i !== 0) {
                externalsStr += ',\n';
            }
            // 不要改这里的缩进，否则最终的结果不好看
            externalsStr += `{
            module_name:'./${libName}',
            module_path:'./${libName}',
            module_from:'engine/${libName}'
        }`;
        }
        externalsStr += '\t]';
        content = content.replace(/const externals = \[([^*].|\n|\r)*\]/gm, externalsStr);
        writeFileSync(vvConfigPath, content, "utf8");
    }
}